import org.junit.Test;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @Auther:chenye
 * @Data:2018/6/12
 * @Description:
 */
public class Java8NewFeatures {
    static Map<String,BigDecimal> bigMap = new HashMap<>();
    {
        bigMap.put("1",new BigDecimal(1));
        bigMap.put("2",new BigDecimal(2));
        bigMap.put("3",new BigDecimal(3));
    }
    static Map<String,Integer> intMap = new HashMap<>();
    {
        intMap.put("1",1);
        intMap.put("2",2);
        intMap.put("3",3);
    }
    @Test
    public void testBigAdd(){
        System.out.println(bigMap.values().stream().reduce(BigDecimal.ZERO,BigDecimal::add));
    }
    @Test
    public void testIntAdd(){
        System.out.println(intMap.values().stream().reduce(0,Integer::max));
    }

    @Test
    public void getParameterName() throws NoSuchMethodException {

        Method[] methods = Hello.class.getMethods();
        for(Method method : methods){
            System.out.println("methodName:"+method.getName());
            for( final Parameter parameter: method.getParameters() ) {
                //需要通过-parameters开启该功能，idea 可以通过在 setting java compiler 中设置 -parameter开启
                /*
                *
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.1</version>
                    <configuration>
                        <compilerArgument>-parameters</compilerArgument>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>
                *
                * */
                System.out.println( "Parameter: " + parameter.getName() );
            }
        }
    }
    @Test
    public void testDefaultInterface(){
        Hello hello = new Hello();
        hello.hello("you");
    }
    @Test
    public void testFunctionalInterface(){
        Interface in = (str)->System.out.println("nihao");
        in.method("str");
    }
    @Test
    //测试双冒号特性
    //Class<T>::new
    //Class::static_method
    //Class::method
    //instance::method
    public void testDoubleColon(){
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.forEach(Hello::hh);//Hello::hh 双冒号作用相当于直接调用Hello类的hh static方法
    }
    @Test
    public void testConsumerFunctional(){
        Consumer<String> consumer = Hello::hh;
        consumer.accept("you");

        Interface i = Hello::hh;//在这里Interface的method方法有点相识将Hello类的hh static方法 包装了一次
        i.method("str");
    }
    @Test
    public void testOptional() throws Throwable {
        Optional optional = Optional.ofNullable(null);
        System.out.println(optional.isPresent());
        System.out.println(optional.orElse("you"));
        System.out.println(optional.orElseGet(()->"xixi"));
        System.out.println(optional.orElseThrow(()->{throw new RuntimeException("null");}));
    }

    @Test
    public void testBiFunction(){
        BiFunction<String,String,String> biFunction = (a,b)->a+b;
        Function<String,String> function = x->x+"function";
        String str = biFunction.andThen(function).apply("yi","er");
        System.out.println(str);
    }
    @Test
    public void testBinaryOperator(){
        Comparator<Integer> comparator = Integer::compareTo;
        Integer big = BinaryOperator.maxBy(comparator).apply(1,2);
        System.out.println(big);
    }
    private static List<String> list = new ArrayList<>();
    {
        list.add("2");
        list.add("1");
        list.add("3");
    }
    @Test
    public void testStream(){
        String str = list.stream().reduce((a,b)->{
            String c = a+b;
            return c+2;
        }).get();

        OptionalDouble optionalDouble = list.stream().mapToInt(a->Integer.parseInt(a)).average();
        System.out.println(optionalDouble.orElseGet(()->new Random(1).nextDouble()));
        System.out.println(optionalDouble.orElseThrow(()->{throw new RuntimeException("123");}));
        System.out.println(optionalDouble.orElse(3));

        Long count = list.stream().mapToInt(a->Integer.parseInt(a)).count();
        System.out.println(count);
        int i = list.stream().mapToInt(a->Integer.parseInt(a)).findAny().getAsInt();
        System.out.println(i);

        int sum = list.stream().mapToInt(a->Integer.parseInt(a)).sum();
        System.out.println(sum);

        boolean b = list.stream().mapToInt(a->Integer.parseInt(a)).allMatch(a->a==1);
        System.out.println(b);
        System.out.println("test filter");
        list.stream().mapToInt(a->Integer.parseInt(a)).filter(a->a==1).forEach(System.out::println);
        System.out.println("test filter end");

        i = list.stream().map(x->Integer.parseInt(x)).sorted(Comparator.comparing(x->x)).findFirst().get();
        System.out.println(i);

    }

    @Test
    public void testStream2(){
//        list.stream().collect(Collectors.toMap(x->x+1,y->y)).forEach((x,y)->System.out.println("key:"+x+"  v:"+y));
        Object str = list.stream().reduce("",(x,y)->x+y);
        System.out.println(str);
        list.stream().mapToInt(Integer::valueOf).min();
    }
    static List<Integer> integers = new ArrayList<>();
    {
        integers.add(1);
        integers.add(2);
        integers.add(3);
        integers.add(4);
        integers.add(5);
        integers.add(6);
        integers.add(7);
    }
    @Test
    public void testStream3(){
        Object obj;
        obj = integers.stream().min(Comparator.comparing(Integer::intValue)).get();
        System.out.println(obj);

        obj = integers.stream().collect(Collectors.counting());
        integers.stream().sorted().forEach(System.out::println);
        System.out.println(obj);
    }
    @Test
    public void testStream4(){
        Object obj;
        Predicate<Integer> predicate = x->x==1;
        predicate.negate();//取反
        obj = integers.stream().anyMatch(predicate);
        System.out.println(obj);
    }
    @Test
    public void testStream5(){
        integers.stream().limit(2).forEach(System.out::println);
    }
    @Test
    public void testStream6(){
        integers.stream().sorted();//从大到小排序

        //Comparator.reverseOrder() 反序
//        integers.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);

        //peek的输出只有在stream流最终转化成对象的时候才会输出。
        integers.stream()
                .filter(x->x>3)
                .peek(System.out::println)
                .map(x->x+1)
                .peek(System.out::println)
                .toArray();
    }
    @Test
    public void testStream7(){
        //通过group分组出来的Map的values是一个java.util.ArrayList
        integers.stream().parallel()
                .filter(x->x>=2)
                .collect(Collectors.groupingBy(x->x)).forEach((x,y)->{
                    System.out.println("key:"+x+" value:"+y+" value-type:"+y.getClass());
        });

    }
    @Test
    public void testStream8(){
        //parallel stream并行的理解
    }


    static List<Person> persons = new ArrayList<>();
    {
        persons.add(new Person("chenye",20));
        persons.add(new Person("xiaoming",24));
        persons.add(new Person("xiaofang",22));
    }
    @Test
    public void testStream9(){
        //map,mapXXX一类的方法，是将参数转化成了一个以参数为主的新stream
        persons.stream().parallel().map(Person::getAge).forEach(System.out::println);
        //forEachOrdered 按照顺序输出
        persons.stream().mapToInt(Person::getAge).forEachOrdered(System.out::println);
    }
    @Test
    public void testStream10(){
        //报错的
//        IntStream.range(0,10).collect(Collectors.toList());
        IntStream.range(0,10).boxed().collect(Collectors.toList()).forEach(System.out::println);
    }

    @Test
    public void testStream11(){
        //求平均值
        System.out.println("平均值");
        System.out.println(integers.stream().collect(Collectors.averagingInt(x->x)));
        //求最大值
        System.out.println("最大值");
        System.out.println(integers.stream().max(Comparator.comparing(Integer::intValue)));
        System.out.println(integers.stream().collect(Collectors.maxBy(Comparator.comparing(Integer::intValue))));
        //求最小值
        System.out.println("最小值");
        System.out.println(integers.stream().min(Comparator.comparing(Integer::intValue)));
        System.out.println(integers.stream().collect(Collectors.minBy(Comparator.comparing(Integer::intValue))));

//        System.out.println(integers.stream().collect());
        //求和
        System.out.println("和");
        System.out.println(integers.stream().reduce(0,(x,y)->x+y));
        System.out.println(integers.stream().collect(Collectors.summingInt(Integer::intValue)));
    }
    @Test
    public void testStream12(){
        //reduce的第三个参数是在stream开启parallel的时候才生效
        System.out.println(Stream.of("1","2","3").reduce("a",(x,y)->x+y,(a,b)->a+b));
        System.out.println(Stream.of("1","2","3").parallel().reduce("a",(x,y)->x+y,(a,b)->a+b));

        System.out.println(Stream.of("ab","cd","ef")
                .parallel()
                .collect(()->new ArrayList<>(),(a,b)->a.add(b),(c,d)->c.add(d)));
    }
    @Test
    public void testStream13(){
        //在开启了并发流后 如果没有使用collect或者reduce时，会出现并发问题。也可以使用同步对列
        integers.parallelStream().forEach(System.out::println);
        System.out.println("===================================");
        integers.stream().parallel().forEach(System.out::println);
    }
    @Test
    public void test(){
        System.err.println( 1 << 2);
        System.err.println( 2 >> 2);
        System.err.println( 1|2|3|4);

    }
    @Test
    public void testByteLength(){
        System.err.println(UUID.randomUUID().toString().getBytes().length);
    }
}

class Hello implements Interface{
    public void test(String str){
        System.out.println(str);
    }
    public void test1(Integer integer){
        System.out.println(integer);
    }

    @Override
    public void hello(String str) {
        System.out.println(str+str);
    }
    public static void hh(String str){
        System.out.println(str);
    }
    public static String hh(){
        return "hh";
    }
    @Override
    public void method(String str) {

    }
}

@FunctionalInterface//声明这个接口是一个函数式接口
    //ps：函数式接口，理解为方便定义lambda表达是的接口，切该接口只有一个接口方法，但是可以有default方法和static 方法
interface Interface{
    void method(String str);
    //接口提供默认的实现方法，但是不能通过该接口直接调用，只能通过实现类调用
    default void hello(String str){System.out.println(str);}
    static String say(){return "123";}
}

class Person{
    private String name;
    private Integer age;

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

